﻿#region Header

/*
Behavioral Rating of Dancing Human Crowds based on Motion Patterns
By

Pascal Hauser 
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

and

Raphael Gfeller
Dipl. Ing. in Informatik, Hochschule für Technik Rapperswil, 2006
Master Thesis, Hochschule für Technik Rapperswil, 2008-2010

*/

#endregion

#region Usings

using System.ComponentModel;
using System.Windows.Markup;
using paravili.Services;
using Sebarf.Diagnostics.Interfaces;
using Sebarf.Services.Interfaces;
using Utils;

#endregion

namespace paravili.Steps {
	/// <summary>
	/// Description of the class
	/// </summary>
	[DefaultProperty("NextStep")]
	[ContentProperty("NextStep")]
	public abstract class ProcessStepWithMeasurement<TSource> : IProcessStep {
		#region Public Properties

		[ServiceRequest]
		public IStatisticValuesProviderService StatisticValuesProviderService { get; set; }

		[ConfigurabelStringValue(Name = "id for the IStatisticValuesProviderService service ")]
		public string TimeMeasurementResultId { get; set; }

		[ConfigurabelBooleanValue(Name = "enable time measurement")]
		public bool IsEnableTimeMeasurement { get; set; }

		/// <summary>
		/// is called after Process
		/// </summary>
		public ProcessStepWithMeasurement<TSource> NextStep { get; set; }

		#endregion

		#region Public Methods

		public ProcessStepWithMeasurement() {
			TimeMeasurementResultId = GetType().Name + "_ProcessTime_Ms";
			PerformanceTimer = new PerformanceTimer();
			IsEnableTimeMeasurement = true;
		}

		/// <summary>
		/// returns if the process step can process the given object
		/// </summary>
		/// <param name="toProcess"></param>
		/// <returns></returns>
		public virtual bool CanProcess(TSource toProcess) {
			return true;
		}

		/// <summary>
		/// process the process step with the given object
		/// </summary>
		/// <param name="toProcess"></param>
		/// <returns></returns>
		public virtual object Process(TSource toProcess) {
			Check.AssertException(CanProcess(toProcess), "cannot process the given object");
#if DEBUG
			if (IsEnableTimeMeasurement && StatisticValuesProviderService != null) {
				PerformanceTimer.Start();
			}
#endif
            TSource toReturn = default(TSource);
            try {
                 toReturn = OnProcess(toProcess);
            } catch {
                throw;
            }
#if DEBUG
			if (IsEnableTimeMeasurement && StatisticValuesProviderService != null) {
				PerformanceTimer.Stop();
				double timeNeeded = PerformanceTimer.ElapsedTimeMilliseconds.Miliseconds;
				StatisticValuesProviderService.SetStatisticValue(TimeMeasurementResultId, (int)timeNeeded);
			}
#endif
			if (NextStep == null) {
				return toReturn;
			}
			else {
                try {
                    return NextStep.Process(toReturn);
                } catch {
                    throw;
                }
			}
		}

		public override string ToString() {
			return GetType().ToString();
		}

		#endregion

		#region Private Methods

		protected abstract TSource OnProcess(TSource toProcess);

		#endregion

		#region Private Fields

		protected PerformanceTimer PerformanceTimer { get; set; }

		#endregion

		#region IProcessStep Members

		public bool CanProcessItem(object o) {
			if (o is TSource) {
				return CanProcess((TSource)o);
			}
			else {
				return false;
			}
		}

		public void ProcessItem(object o) {
			Process((TSource)o);
		}

		public virtual IProcessStep GetNextStep() {
			return NextStep;
		}

		#endregion
	}
}